﻿// ***************************************************************
//  variant   version:  1.0   ·  date: 05/24/2010
//  -------------------------------------------------------------
//  
//  -------------------------------------------------------------
//  Copyright (C) 2010 - All Rights Reserved
// ***************************************************************
// 
// ***************************************************************
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
#pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#ifndef ccs_util_data_variant_h__
#define ccs_util_data_variant_h__

#include <boost/type_traits.hpp>
#include <sstream>

#include <moeutil/prerequisite.h>

#include "ccs_util/event.hpp"
#include "ccs_util/data/any_data.hpp"


namespace ccs
{
	class raw_variant : public any_data
	{
	public:
		template<typename VarType> struct is_comfort : public boost::false_type{};

		template<> struct is_comfort<bool> : public boost::true_type{};
		template<> struct is_comfort<char> : public boost::true_type{};
		template<> struct is_comfort<int16> : public boost::true_type{};
		template<> struct is_comfort<uint16> : public boost::true_type{};
		template<> struct is_comfort<int32> : public boost::true_type{};
		template<> struct is_comfort<uint32> : public boost::true_type{};
		template<> struct is_comfort<int64> : public boost::true_type{};
		template<> struct is_comfort<uint64> : public boost::true_type{};
		template<> struct is_comfort<float> : public boost::true_type{};
		template<> struct is_comfort<double> : public boost::true_type{};
		
		enum raw_type
		{
			boolean, ch, i16, ui16, i32, ui32, i64, ui64, r32, r64
		};
		union un_raw_type
		{
			un_raw_type() :uint64_(0){}

			bool boolean_;
			char c_;
			int16 int16_;
			uint16 uint16_;
			int32 int32_;
			uint32 uint32_;
			int64 int64_;
			uint64 uint64_;
			float real_;
			double db_;
		};

		raw_variant(bool var)
			: var_type_(boolean)
		{
			var_.boolean_ = var;
		}
		raw_variant(char var)
			: var_type_(ch)
		{
			var_.c_ = var;
		}
		raw_variant(int16 var)
			: var_type_(i16)
		{
			var_.int16_ = var;
		}
		raw_variant(uint16 var)
			: var_type_(ui16)
		{
			var_.uint16_ = var;
		}
		raw_variant(int32 var)
			: var_type_(i32)
		{
			var_.int32_ = var;
		}
		raw_variant(uint32 var)
			: var_type_(ui32)
		{
			var_.uint32_ = var;
		}
		raw_variant(int64 var)
			: var_type_(i64)
		{
			var_.int64_ = var;
		}
		raw_variant(uint64 var)
			: var_type_(ui64)
		{
			var_.uint64_ = var;
		}
		raw_variant(float var)
			: var_type_(r32)
		{
			var_.real_ = var;
		}
		raw_variant(double var)
			: var_type_(r64)
		{
			var_.db_ = var;
		}

		template<typename VarType>
		raw_variant& operator = (VarType const& var)
		{
			new (this) raw_variant(var);
			return (*this);
		}

		operator bool&()	{ return var_.boolean_; }
		operator char&()	{ return var_.c_; }
		operator int16&()	{ return var_.int16_; }
		operator uint16&()	{ return var_.uint16_; }
		operator int32&()	{ return var_.int32_; }
		operator uint32&()	{ return var_.uint32_; }
		operator int64&()	{ return var_.int64_; }
		operator uint64&()	{ return var_.uint64_; }
		operator float&()	{ return var_.real_; }
		operator double&()	{ return var_.db_; }

		un_raw_type var_;
		raw_type var_type_;

	protected:
		virtual void serialise(iarchive& iar);
		virtual void serialise(oarchive& oar);
		void _release_object();
	};

	template<typename VarType>
	class custom_variant : public any_data
	{
	public:
		custom_variant(VarType const& var)
			: var_(var)
		{
			asmsplit_set_self_event(boost::is_base_of<basic_self_event_data, VarType>());
		}

		void asmsplit_set_self_event(boost::true_type const&)
		{
			self_event_ = true;
		}

		void asmsplit_set_self_event(boost::false_type const&)
		{
			self_event_ = false;
		}

		static custom_variant* create_instance(VarType const& var)
		{
			return ccs_new_args(custom_variant, var);
		}

		static any_data_ptr create_instance_ptr(VarType const& var)
		{
			return any_data_ptr(create_instance(var));
		}

		template<typename VarType>
		custom_variant& operator = (VarType const& var)
		{
			new (this) custom_variant(var);
			return (*this);
		}

		operator VarType&()
		{
			return var_;
		}

		event::connection observe(std::string const& eventName,	event::slot2 const& handler)
		{
			return asmsplit_observe(eventName, handler, boost::is_base_of<basic_self_event_data, VarType>());
		}

		event::connection asmsplit_observe(std::string const& eventName, event::slot2 const& handler, boost::true_type const&)
		{
			var_.observe(eventName, handler);
		}

		event::connection asmsplit_observe(std::string const& eventName, event::slot2 const& handler, boost::false_type const&)
		{
			throw std::exception("NoImplement");
		}

	protected:
		void serialise(iarchive& iar)
		{
			iar >> var_;
		}
		void serialise(oarchive& oar)
		{
			oar << var_;
		}
		void _release_object()
		{
			ccs_delete(this);
		}

		VarType var_;
	};

	template<typename VarType>
	inline custom_variant<VarType>* create_variant(VarType const& var)
	{
		return custom_variant<VarType>::create_instance(var);
	}

	template<typename VarType>
	inline any_data_ptr create_variant_ptr(VarType const& var)
	{
		return custom_variant<VarType>::create_instance_ptr(var);
	}
}


#endif // ccs_util_data_variant_h__